<?php

namespace System\library\loader;

/**
 * <b>Class</b> :        Css<br>
 * <b>Fonction</b> :     Permet faire un css global et de le mettre en cache
 * <br>
 * @version              1.0
 * @author               Dread <dreadlokeur@gmail.com>
 * @license              Licence publique générale GNU http://www.gnu.org/licenses/gpl.html
 * @copyright            Copyright 2011 - MidichloriansPHP and contributors
 * @package              System
 * @subpackage           library\loader
 *
 * //TODO compress css file and rewritte path into css file
 */
class CssLoader {

    /**
     * L'attribut qui stock si l'on doit mettre en cache le css
     *
     * @access private
     * @var bool
     */
    private $_cached = true;
    /**
     * L'attribut qui stock le nom du repertoire de cache
     *
     * @access private
     * @var string
     */
    private $_cacheDir = '';
    /**
     * L'attribut qui stock le nom du css de sortie
     *
     * @access private
     * @var string
     */
    private $_cacheName = 'style.css';
    /**
     * L'attribut qui stock le nom du hash generer, lors de la mise en cache du css
     *
     * @access private
     * @var string
     */
    private $_cacheNameHash = 'css_hash';
    /**
     * L'attribut qui stock les divers css à stocker dans le css de sortie
     *
     * @access private
     * @var array
     */
    private $_files = array();
    /**
     * L'attribut qui stock l'information: on force l'update du cache ou pas
     *
     * @access private
     * @var array
     */
    private $_forceCacheUpdate = false;

    /**
     * Permet de définir si on va mettre en cache le css de fin ou pas
     *
     * @access public
     * @param bool $bool en cache: oui ou non
     * @return void
     */
    public function setCached($bool) {
        if (!is_bool($bool))
            throw new \Exception('Cached parameter must be a boolean');
        $this->_cached = (bool) $bool;
        return $this;
    }

    /**
     * Permet de définir le nom du css mit en cache
     *
     * @access public
     * @param string $cacheName nom du css en cache
     * @return void
     */
    public function setCacheName($cacheName) {
        if (!is_string($cacheName))
            throw new \Exception('cacheName parameter must be a string');
        $this->_cacheName = $cacheName;
        return $this;
    }

    /**
     * Permet de définir le nom du hash de cache du css
     *
     * @access public
     * @param string $cacheNameHash le nom du hash de cache du css
     * @return void
     */
    public function setCacheHashName($cacheHashName) {
        if (!is_string($cacheName))
            throw new \Exception('cacheNameHash parameter must be a string');
        $this->_cacheNameHash = $cacheHashName;
        return $this;
    }

    /**
     * Permet de définir si l'on veut forcer la mise à jour du cache
     *
     * @access public
     * @param bool $bool oui, non
     * @return void
     */
    public function setForceCacheUpdate($bool) {
        if (!is_bool($bool))
            throw new \Exception('ForceCacheUpdate parameter must be a boolean');
        $this->_forceCacheUpdate = (bool) $bool;
        return $this;
    }

    /**
     * Permet de définir le répertoire de mise en cache du css
     *
     * @access public
     * @param string $directory le répertoire de cache
     * @return void
     */
    public function setCacheDir($directory) {
        if (!is_dir($directory))
            throw new \Exception('Directory ' . $directory . ' don\'t exist');
        if (!is_writable($directory))
            throw new \Exception('Directory ' . $directory . ' is not writtable');
        $this->_cacheDir = $directory;
        return $this;
    }

    /**
     * Permet d'ajouter un fichier css au css final
     *
     * @access public
     * @param string $file le fichier css à ajouter au css final
     * @return void
     */
    public function addFile($file) {
        if (!file_exists($file) || !is_file($file))
            throw new \Exception('File ' . $file . ' don\'t exist');
        $this->_files[] = array(
            'name' => $file,
            'lastUpdate' => filemtime($file),
        );
    }

    /**
     * Permet d'obtenir le css final mit en cache(si demandé)
     *
     * @access public
     * @param void
     * @return void
     */
    public function output() {
        if ($this->_cached) {
            if (!is_dir($this->_cacheDir))
                throw new \Exception('Cache directory not setted');

            if ($this->_cacheExpired() || $this->_forceCacheUpdate)
                $this->_generateCache();
        }else
            echo $this->_getContent();
    }

    /**
     * Permet de regarder si le cache du css final est expiré: un fichier css à été modifié, ou le cache n'existe pas encore...
     * 
     * @access private
     * @param void
     * @return bool retourne true si le cache est expiré: hash différent, cache vide...
     */
    private function _cacheExpired() {
        if (!file_exists($this->_cacheDir . $this->_cacheName) || !file_exists($this->_cacheDir . $this->_cacheNameHash))
            return true;
        // Check Hash liste files
        $hash = file_get_contents($this->_cacheDir . $this->_cacheNameHash);
        if ($hash != md5(serialize($this->_files)))
            return true;
        // Check file updated
        $cacheDate = filemtime($this->_cacheDir . $this->_cacheName);
        foreach ($this->_files as $file) {
            if ($cacheDate < $file['lastUpdate'])
                return true;
        }
    }

    /**
     * Permet de generer le cache
     * 
     * @access private
     * @param void
     * @return void
     */
    private function _generateCache() {
        file_put_contents($this->_cacheDir . $this->_cacheName, $this->_getContent());
        file_put_contents($this->_cacheDir . $this->_cacheNameHash, md5(serialize($this->_files)));
    }

    /**
     * Permet d'obtenir le css final: cumul de tous les css ajoutés
     * 
     * @access private
     * @param void
     * @return string le contenu du css final
     */
    private function _getContent() {
        $content = '';
        //On parcours les fichiers css ajoutés
        foreach ($this->_files as $file) {
            $content .= file_get_contents($file['name']);
        }
        return $content;
    }

}

?>